R Markdown

(Copied from this)

You can use R Markdown (.Rmd) to:

  • save and execute code
  • generate high quality, reproducible reports that can be shared with an audience

Basic structure consists of:

  • YAML metadata
  • Text (markdown)
  • Code chunks

Can edit in Visual mode, more like a Word doc. (Click on ‘Visual’, next to ‘Source’ at the top of the code editor.)

To see your R markdown output file (e.g. html), you knit the .Rmd file by clicking the Knit button at the top of the code editor or ctrl-shift-k.

YAML

The YAML header is used to set the output format and output options.

Here, we’ve added a table of contents using the toc: true.

Have a look at the cheat sheet and try to add some more features:

Exercise: Make the table of contents floating.

Add toc_float: TRUE to the YAML.

Exercise: Give an option to download the .Rmd source code.

Add code_download: TRUE to the YAML.

Exercise: Hide all the code chunks by default and allow users to show/hide code as desired.

Add code_folding: “hide” to the YAML.

We can generate a custom R markdown template to use in the future.

Text

Makes clear documentation easier.

You can navigate through the headers (#Heading 1, ##Heading 2 etc) like a table of contents in the code editor by clicking ‘Outline’ in the top right.

Have a look at the cheat sheet and try the following exercises.

Exercise: Bold and italicise some words in the list below.

  • Always leave a blank line between a list and the text above for the bullet points to render properly
  • assessing current practice (italics)
  • recording an action plan (bold)
  • monitoring quality improvement

Exercise: Create a link to the page on Impact reports on the NICE website.

See impact reports.

Exercise: Embed an image of the NICE logo and add some alt text.

This standard method doesn’t seem to allow adding alt text, but the text in the square brackets is displayed as a caption at the bottom of the image.

NICE logo

Need to use this method with fig.alt in chunk options for alt text.

knitr::include_graphics("https://www.nice.org.uk/Media/Default/About/Branding-guidelines/Logos/master-logo1.png")

NICE logo

This line contains some inline code to give the time of rendering: 2022-06-08 13:05:26.

Code chunks

Exercise: Insert a code chunk. Try using a keyboard shortcut (ctrl-alt-i).

Labelling your chunks (e.g. ‘load_doacs’ in the chunk below) means you can navigate to each section easily via the button at the bottom of the code editor (orange square with hash symbol).

Tabs

A demo using the DOACS data from before.

The line chart and table sections are in tabs below the header ‘Tabs’ because we’ve specified {.tabset}.

You should run all the chunks above a chunk before running the chunk itself to make sure your code works sequentially, when working in the code editor (i.e. not knitting). Click on the grey triangle with the green bar (‘Run all chunks above’) in the top right of a chunk (ctrl-alt-shift-p).

To run a chunk, ctrl-shift-enter with the cursor anywhere in the chunk (or the green play button).

Line chart

Exercise: Plot a line chart showing prescribing of all doacs over the last 2 years (reuse previous code from DOACS exercises). Try making it interactive by using the function ggplotly() from the plotly package (install the package first).

Table

There are many packages available for plotting tables in R markdown.

We’ll use reactable here. Install the package.

Exercise: Modify this table to make it filterable and searchable. Try using an aggregate function to give the sum items for each chemical.

doacs_df %>% 
    filter(year(date) == 2020) %>% 
    group_by(chemical, date) %>% 
    summarise(sum_items = sum(items)) %>% 
    reactable(
        .,
        filterable = TRUE,
        searchable = TRUE,
        groupBy = "chemical",
        columns = list(
            sum_items = colDef(aggregate = "sum")
        )
    )

Chunk options

Chunk options allow control over chunk outputs. See some options here.

Exercise: Add an option to the load_doacs chunk so the chunk still runs, but is not shown in the final document.

Add include = FALSE to the chunk. Remember to use a comma after the chunk label when adding chunk options.

Exercise: Add an option to the doacs_line chunk to hide the code which generates the line graph.

Add echo = FALSE to the chunk. echo prevents the code from appearing in the output file but not the results of the code. It’s often used for figures, where you want to show a chart but hide the code which generated the chart.

Exercise: Add an option to the doacs_table chunk to hide the message about summarise grouping.

Add message = FALSE.

Exercise: Override the global options in the setup chunk so every chunk runs and any results are generated, but the code is not shown.

Change to echo = FALSE in knitr::opts_chunk$set(echo = TRUE). We want to use echo = FALSE rather than include = FALSE as we still want to see our line chart and table.

Parameters

You can include parameters to rerun a report with different values. Parameters are specified in the YAML, given a default value (here, year: 2020), and used via params$name (e.g. params$year). (Note the backslash in here between params and name, visible only the .Rmd, is to escape the markdown syntax as dollar signs are used to display equations in markdown.)

# Changing the year to a parameter
doacs_df %>% 
    filter(year(date) == params$year) %>% 
    group_by(chemical, date) %>% 
    summarise(sum_items = sum(items)) %>% 
    reactable(
        .,
        groupBy = "chemical"
    )

Exercise: Try re-rendering the report with the year 2021 using the Rstudio IDE.

Click on the triangle next to ‘Knit’, ‘Knit with Parameters’, change 2020 to 2021.

LS0tDQp0aXRsZTogIlIgbWFya2Rvd24gYmFzaWNzIg0KYXV0aG9yOiAiSW1wYWN0IHRlYW0iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6IA0KICAgIGh0bWxfZG9jdW1lbnQ6DQogICAgICAgIHRvYzogdHJ1ZQ0KICAgICAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICAgICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgICAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIg0KcGFyYW1zOg0KICAgIHllYXI6IDIwMjANCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShyZWFjdGFibGUpDQpgYGANCg0KIyBSIE1hcmtkb3duDQoNCihDb3BpZWQgZnJvbSBbdGhpc10oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTEuaHRtbCkpDQoNCllvdSBjYW4gdXNlIFIgTWFya2Rvd24gKC5SbWQpIHRvOg0KDQotIHNhdmUgYW5kIGV4ZWN1dGUgY29kZQ0KLSBnZW5lcmF0ZSBoaWdoIHF1YWxpdHksIHJlcHJvZHVjaWJsZSByZXBvcnRzIHRoYXQgY2FuIGJlIHNoYXJlZCB3aXRoIGFuIGF1ZGllbmNlDQoNCkJhc2ljIHN0cnVjdHVyZSBjb25zaXN0cyBvZjoNCg0KLSBZQU1MIG1ldGFkYXRhDQotIFRleHQgKG1hcmtkb3duKQ0KLSBDb2RlIGNodW5rcw0KDQpDYW4gZWRpdCBpbiBWaXN1YWwgbW9kZSwgbW9yZSBsaWtlIGEgV29yZCBkb2MuIChDbGljayBvbiAnVmlzdWFsJywgbmV4dCB0byAnU291cmNlJyBhdCB0aGUgdG9wIG9mIHRoZSBjb2RlIGVkaXRvci4pDQoNClRvIHNlZSB5b3VyIFIgbWFya2Rvd24gb3V0cHV0IGZpbGUgKGUuZy4gaHRtbCksIHlvdSBrbml0IHRoZSAuUm1kIGZpbGUgYnkgY2xpY2tpbmcgdGhlIEtuaXQgYnV0dG9uIGF0IHRoZSB0b3Agb2YgdGhlIGNvZGUgZWRpdG9yIG9yIGN0cmwtc2hpZnQtay4NCg0KIyBZQU1MDQoNClRoZSBZQU1MIGhlYWRlciBpcyB1c2VkIHRvIHNldCB0aGUgb3V0cHV0IGZvcm1hdCBhbmQgb3V0cHV0IG9wdGlvbnMuDQoNCkhlcmUsIHdlJ3ZlIGFkZGVkIGEgdGFibGUgb2YgY29udGVudHMgdXNpbmcgdGhlIHRvYzogdHJ1ZS4NCg0KSGF2ZSBhIGxvb2sgYXQgdGhlIFtjaGVhdCBzaGVldF0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTE1Lmh0bWwpIGFuZCB0cnkgdG8gYWRkIHNvbWUgbW9yZSBmZWF0dXJlczoNCg0KPiBFeGVyY2lzZTogTWFrZSB0aGUgdGFibGUgb2YgY29udGVudHMgZmxvYXRpbmcuDQoNCkFkZCB0b2NfZmxvYXQ6IFRSVUUgdG8gdGhlIFlBTUwuDQoNCj4gRXhlcmNpc2U6IEdpdmUgYW4gb3B0aW9uIHRvIGRvd25sb2FkIHRoZSAuUm1kIHNvdXJjZSBjb2RlLg0KDQpBZGQgY29kZV9kb3dubG9hZDogVFJVRSB0byB0aGUgWUFNTC4NCg0KPiBFeGVyY2lzZTogSGlkZSBhbGwgdGhlIGNvZGUgY2h1bmtzIGJ5IGRlZmF1bHQgYW5kIGFsbG93IHVzZXJzIHRvIHNob3cvaGlkZSBjb2RlIGFzIGRlc2lyZWQuDQoNCkFkZCBjb2RlX2ZvbGRpbmc6ICJoaWRlIiB0byB0aGUgWUFNTC4NCg0KV2UgY2FuIGdlbmVyYXRlIGEgY3VzdG9tIFIgbWFya2Rvd24gdGVtcGxhdGUgdG8gdXNlIGluIHRoZSBmdXR1cmUuDQoNCiMgVGV4dA0KDQpNYWtlcyBjbGVhciBkb2N1bWVudGF0aW9uIGVhc2llci4NCg0KWW91IGNhbiBuYXZpZ2F0ZSB0aHJvdWdoIHRoZSBoZWFkZXJzICgjSGVhZGluZyAxLCAjI0hlYWRpbmcgMiBldGMpIGxpa2UgYSB0YWJsZSBvZiBjb250ZW50cyBpbiB0aGUgY29kZSBlZGl0b3IgYnkgY2xpY2tpbmcgJ091dGxpbmUnIGluIHRoZSB0b3AgcmlnaHQuDQoNCkhhdmUgYSBsb29rIGF0IHRoZSBbY2hlYXQgc2hlZXRdKGh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2xlc3Nvbi0xNS5odG1sKSBhbmQgdHJ5IHRoZSBmb2xsb3dpbmcgZXhlcmNpc2VzLg0KDQo+IEV4ZXJjaXNlOiBCb2xkIGFuZCBpdGFsaWNpc2Ugc29tZSB3b3JkcyBpbiB0aGUgbGlzdCBiZWxvdy4NCg0KLSBBbHdheXMgbGVhdmUgYSBibGFuayBsaW5lIGJldHdlZW4gYSBsaXN0IGFuZCB0aGUgdGV4dCBhYm92ZSBmb3IgdGhlIGJ1bGxldCBwb2ludHMgdG8gcmVuZGVyIHByb3Blcmx5DQotIGFzc2Vzc2luZyAqY3VycmVudCBwcmFjdGljZSogKGl0YWxpY3MpDQotIHJlY29yZGluZyAqKmFuIGFjdGlvbiBwbGFuKiogKGJvbGQpDQotIG1vbml0b3JpbmcgcXVhbGl0eSBpbXByb3ZlbWVudA0KDQo+IEV4ZXJjaXNlOiBDcmVhdGUgYSBsaW5rIHRvIHRoZSBwYWdlIG9uIEltcGFjdCByZXBvcnRzIG9uIHRoZSBOSUNFIHdlYnNpdGUuDQoNClNlZSBbaW1wYWN0IHJlcG9ydHNdKGh0dHBzOi8vd3d3Lm5pY2Uub3JnLnVrL2Fib3V0L3doYXQtd2UtZG8vaW50by1wcmFjdGljZS9tZWFzdXJpbmctdGhlLXVwdGFrZS1vZi1uaWNlLWd1aWRhbmNlL2ltcGFjdC1vZi1ndWlkYW5jZSkuDQoNCj4gRXhlcmNpc2U6IEVtYmVkIGFuIFtpbWFnZSBvZiB0aGUgTklDRSBsb2dvXShodHRwczovL3d3dy5uaWNlLm9yZy51ay9icmFuZC9vdXItbG9nbykgYW5kIGFkZCBzb21lIGFsdCB0ZXh0Lg0KDQpUaGlzIHN0YW5kYXJkIG1ldGhvZCBkb2Vzbid0IHNlZW0gdG8gYWxsb3cgYWRkaW5nIGFsdCB0ZXh0LCBidXQgdGhlIHRleHQgaW4gdGhlIHNxdWFyZSBicmFja2V0cyBpcyBkaXNwbGF5ZWQgYXMgYSBjYXB0aW9uIGF0IHRoZSBib3R0b20gb2YgdGhlIGltYWdlLg0KDQohW05JQ0UgbG9nb10oaHR0cHM6Ly93d3cubmljZS5vcmcudWsvTWVkaWEvRGVmYXVsdC9BYm91dC9CcmFuZGluZy1ndWlkZWxpbmVzL0xvZ29zL21hc3Rlci1sb2dvMS5wbmcpDQoNCk5lZWQgdG8gdXNlIHRoaXMgbWV0aG9kIHdpdGggZmlnLmFsdCBpbiBjaHVuayBvcHRpb25zIGZvciBhbHQgdGV4dC4NCg0KYGBge3IsIGZpZy5hbHQgPSAiTklDRSBsb2dvIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3d3dy5uaWNlLm9yZy51ay9NZWRpYS9EZWZhdWx0L0Fib3V0L0JyYW5kaW5nLWd1aWRlbGluZXMvTG9nb3MvbWFzdGVyLWxvZ28xLnBuZyIpDQpgYGANCg0KDQo8IS0tIFdoYXQgZG8geW91IHRoaW5rIHRoaXMgbGluZSBpcz8gSXQncyBhIGNvbW1lbnQgKGN0cmwtc2hpZnQtYykgLS0+DQoNClRoaXMgbGluZSBjb250YWlucyBzb21lIFtpbmxpbmUgY29kZV0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTQuaHRtbCkgdG8gZ2l2ZSB0aGUgdGltZSBvZiByZW5kZXJpbmc6IGByIG5vdygpYC4NCg0KIyBDb2RlIGNodW5rcw0KDQo+IEV4ZXJjaXNlOiBJbnNlcnQgYSBjb2RlIGNodW5rLiBUcnkgdXNpbmcgYSBrZXlib2FyZCBzaG9ydGN1dCAoY3RybC1hbHQtaSkuDQoNCkxhYmVsbGluZyB5b3VyIGNodW5rcyAoZS5nLiAnbG9hZF9kb2FjcycgaW4gdGhlIGNodW5rIGJlbG93KSBtZWFucyB5b3UgY2FuIG5hdmlnYXRlIHRvIGVhY2ggc2VjdGlvbiBlYXNpbHkgdmlhIHRoZSBidXR0b24gYXQgdGhlIGJvdHRvbSBvZiB0aGUgY29kZSBlZGl0b3IgKG9yYW5nZSBzcXVhcmUgd2l0aCBoYXNoIHN5bWJvbCkuDQoNCiMjIFRhYnMgey50YWJzZXR9DQoNCkEgZGVtbyB1c2luZyB0aGUgRE9BQ1MgZGF0YSBmcm9tIGJlZm9yZS4NCg0KVGhlIGxpbmUgY2hhcnQgYW5kIHRhYmxlIHNlY3Rpb25zIGFyZSBpbiB0YWJzIGJlbG93IHRoZSBoZWFkZXIgJ1RhYnMnIGJlY2F1c2Ugd2UndmUgc3BlY2lmaWVkIHsudGFic2V0fS4NCg0KWW91IHNob3VsZCBydW4gYWxsIHRoZSBjaHVua3MgYWJvdmUgYSBjaHVuayBiZWZvcmUgcnVubmluZyB0aGUgY2h1bmsgaXRzZWxmIHRvIG1ha2Ugc3VyZSB5b3VyIGNvZGUgd29ya3Mgc2VxdWVudGlhbGx5LCB3aGVuIHdvcmtpbmcgaW4gdGhlIGNvZGUgZWRpdG9yIChpLmUuIG5vdCBrbml0dGluZykuIENsaWNrIG9uIHRoZSBncmV5IHRyaWFuZ2xlIHdpdGggdGhlIGdyZWVuIGJhciAoJ1J1biBhbGwgY2h1bmtzIGFib3ZlJykgaW4gdGhlIHRvcCByaWdodCBvZiBhIGNodW5rIChjdHJsLWFsdC1zaGlmdC1wKS4NCg0KVG8gcnVuIGEgY2h1bmssIGN0cmwtc2hpZnQtZW50ZXIgd2l0aCB0aGUgY3Vyc29yIGFueXdoZXJlIGluIHRoZSBjaHVuayAob3IgdGhlIGdyZWVuIHBsYXkgYnV0dG9uKS4NCg0KYGBge3IgbG9hZF9kb2FjcywgaW5jbHVkZSA9IEZBTFNFfQ0KIyBNYWtlIHN1cmUgdGhpcyAuUm1kIGlzIHNhdmVkIGluIHRoZSBzYW1lIGZvbGRlciBhcyB3aGVyZSB0aGUgRE9BQ1MgZGF0YXNldCBmcm9tIHRoZSBwcmV2aW91cyBzZXNzaW9uIGlzDQojIENoYW5nZSB0aGUgZmlsZSBuYW1lIHRvIHdoYXRldmVyIHlvdSd2ZSBzYXZlZCBpdCBhcw0KZG9hY3NfZGYgPC0gcmVhZF9jc3YoIkRPQUNTX2RhdGEuY3N2IiwgDQogICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSAiRGNjY2RkZCIpDQpgYGANCg0KIyMjIExpbmUgY2hhcnQNCg0KPiBFeGVyY2lzZTogUGxvdCBhIGxpbmUgY2hhcnQgc2hvd2luZyBwcmVzY3JpYmluZyBvZiBhbGwgZG9hY3Mgb3ZlciB0aGUgbGFzdCAyIHllYXJzIChyZXVzZSBwcmV2aW91cyBjb2RlIGZyb20gRE9BQ1MgZXhlcmNpc2VzKS4gVHJ5IG1ha2luZyBpdCBpbnRlcmFjdGl2ZSBieSB1c2luZyB0aGUgZnVuY3Rpb24gZ2dwbG90bHkoKSBmcm9tIHRoZSBwbG90bHkgcGFja2FnZSAoaW5zdGFsbCB0aGUgcGFja2FnZSBmaXJzdCkuDQoNCmBgYHtyIGRvYWNzX2xpbmUsIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0KDQpnIDwtIGRvYWNzX2RmICU+JSANCiAgICBmaWx0ZXIoeWVhcihkYXRlKSAlaW4lIGMoMjAyMCwgMjAyMSkpICU+JSANCiAgICBncm91cF9ieShjaGVtaWNhbCwgZGF0ZSkgJT4lIA0KICAgIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShpdGVtcykpICU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gdG90YWwsIGNvbG91ciA9IGNoZW1pY2FsKSkgKw0KICAgIGdlb21fbGluZSgpDQoNCmdncGxvdGx5KGcpDQoNCmBgYA0KDQojIyMgVGFibGUNCg0KVGhlcmUgYXJlIFttYW55IHBhY2thZ2VzIGF2YWlsYWJsZV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLWNvb2tib29rL3RhYmxlLW90aGVyLmh0bWwpIGZvciBwbG90dGluZyB0YWJsZXMgaW4gUiBtYXJrZG93bi4NCg0KV2UnbGwgdXNlIFtyZWFjdGFibGVdKGh0dHBzOi8vZ2xpbi5naXRodWIuaW8vcmVhY3RhYmxlLykgaGVyZS4gSW5zdGFsbCB0aGUgcGFja2FnZS4NCg0KPiBFeGVyY2lzZTogTW9kaWZ5IHRoaXMgdGFibGUgdG8gbWFrZSBpdCBmaWx0ZXJhYmxlIGFuZCBzZWFyY2hhYmxlLiBUcnkgW3VzaW5nIGFuIGFnZ3JlZ2F0ZSBmdW5jdGlvbl0oaHR0cHM6Ly9nbGluLmdpdGh1Yi5pby9yZWFjdGFibGUvYXJ0aWNsZXMvZXhhbXBsZXMuaHRtbCNncm91cGluZy1hbmQtYWdncmVnYXRpb24pIHRvIGdpdmUgdGhlIHN1bSBpdGVtcyBmb3IgZWFjaCBjaGVtaWNhbC4NCg0KYGBge3IgZG9hY3NfdGFibGUsIG1lc3NhZ2UgPSBGQUxTRX0NCmRvYWNzX2RmICU+JSANCiAgICBmaWx0ZXIoeWVhcihkYXRlKSA9PSAyMDIwKSAlPiUgDQogICAgZ3JvdXBfYnkoY2hlbWljYWwsIGRhdGUpICU+JSANCiAgICBzdW1tYXJpc2Uoc3VtX2l0ZW1zID0gc3VtKGl0ZW1zKSkgJT4lIA0KICAgIHJlYWN0YWJsZSgNCiAgICAgICAgLiwNCiAgICAgICAgZmlsdGVyYWJsZSA9IFRSVUUsDQogICAgICAgIHNlYXJjaGFibGUgPSBUUlVFLA0KICAgICAgICBncm91cEJ5ID0gImNoZW1pY2FsIiwNCiAgICAgICAgY29sdW1ucyA9IGxpc3QoDQogICAgICAgICAgICBzdW1faXRlbXMgPSBjb2xEZWYoYWdncmVnYXRlID0gInN1bSIpDQogICAgICAgICkNCiAgICApDQpgYGANCg0KIyMgQ2h1bmsgb3B0aW9ucw0KDQpDaHVuayBvcHRpb25zIGFsbG93IGNvbnRyb2wgb3ZlciBjaHVuayBvdXRwdXRzLiBTZWUgW3NvbWUgb3B0aW9ucyBoZXJlXShodHRwczovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9sZXNzb24tMy5odG1sKS4NCg0KPiBFeGVyY2lzZTogQWRkIGFuIG9wdGlvbiB0byB0aGUgbG9hZF9kb2FjcyBjaHVuayBzbyB0aGUgY2h1bmsgc3RpbGwgcnVucywgYnV0IGlzIG5vdCBzaG93biBpbiB0aGUgZmluYWwgZG9jdW1lbnQuDQoNCkFkZCBpbmNsdWRlID0gRkFMU0UgdG8gdGhlIGNodW5rLiBSZW1lbWJlciB0byB1c2UgYSBjb21tYSBhZnRlciB0aGUgY2h1bmsgbGFiZWwgd2hlbiBhZGRpbmcgY2h1bmsgb3B0aW9ucy4NCg0KPiBFeGVyY2lzZTogQWRkIGFuIG9wdGlvbiB0byB0aGUgZG9hY3NfbGluZSBjaHVuayB0byBoaWRlIHRoZSBjb2RlIHdoaWNoIGdlbmVyYXRlcyB0aGUgbGluZSBncmFwaC4NCg0KQWRkIGVjaG8gPSBGQUxTRSB0byB0aGUgY2h1bmsuIGVjaG8gcHJldmVudHMgdGhlIGNvZGUgZnJvbSBhcHBlYXJpbmcgaW4gdGhlIG91dHB1dCBmaWxlIGJ1dCBub3QgdGhlIHJlc3VsdHMgb2YgdGhlIGNvZGUuIEl0J3Mgb2Z0ZW4gdXNlZCBmb3IgZmlndXJlcywgd2hlcmUgeW91IHdhbnQgdG8gc2hvdyBhIGNoYXJ0IGJ1dCBoaWRlIHRoZSBjb2RlIHdoaWNoIGdlbmVyYXRlZCB0aGUgY2hhcnQuDQoNCj4gRXhlcmNpc2U6IEFkZCBhbiBvcHRpb24gdG8gdGhlIGRvYWNzX3RhYmxlIGNodW5rIHRvIGhpZGUgdGhlIG1lc3NhZ2UgYWJvdXQgc3VtbWFyaXNlIGdyb3VwaW5nLg0KDQpBZGQgbWVzc2FnZSA9IEZBTFNFLg0KDQo+IEV4ZXJjaXNlOiBPdmVycmlkZSB0aGUgZ2xvYmFsIG9wdGlvbnMgaW4gdGhlIHNldHVwIGNodW5rIHNvIGV2ZXJ5IGNodW5rIHJ1bnMgYW5kIGFueSByZXN1bHRzIGFyZSBnZW5lcmF0ZWQsIGJ1dCB0aGUgY29kZSBpcyBub3Qgc2hvd24uDQoNCkNoYW5nZSB0byBlY2hvID0gRkFMU0UgaW4ga25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKS4gV2Ugd2FudCB0byB1c2UgZWNobyA9IEZBTFNFIHJhdGhlciB0aGFuIGluY2x1ZGUgPSBGQUxTRSBhcyB3ZSBzdGlsbCB3YW50IHRvIHNlZSBvdXIgbGluZSBjaGFydCBhbmQgdGFibGUuDQoNCiMjIFBhcmFtZXRlcnMNCg0KWW91IGNhbiBbaW5jbHVkZSBwYXJhbWV0ZXJzXShodHRwczovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9sZXNzb24tNi5odG1sKSB0byByZXJ1biBhIHJlcG9ydCB3aXRoIGRpZmZlcmVudCB2YWx1ZXMuIFBhcmFtZXRlcnMgYXJlIHNwZWNpZmllZCBpbiB0aGUgWUFNTCwgZ2l2ZW4gYSBkZWZhdWx0IHZhbHVlIChoZXJlLCB5ZWFyOiAyMDIwKSwgYW5kIHVzZWQgdmlhIHBhcmFtc1wkbmFtZSAoZS5nLiBwYXJhbXMkeWVhcikuIChOb3RlIHRoZSBiYWNrc2xhc2ggaW4gaGVyZSBiZXR3ZWVuIHBhcmFtcyBhbmQgbmFtZSwgdmlzaWJsZSBvbmx5IHRoZSAuUm1kLCBpcyB0byBlc2NhcGUgdGhlIG1hcmtkb3duIHN5bnRheCBhcyBkb2xsYXIgc2lnbnMgYXJlIHVzZWQgdG8gZGlzcGxheSBlcXVhdGlvbnMgaW4gbWFya2Rvd24uKQ0KDQpgYGB7ciBkb2Fjc190YWJsZV9wYXJhbXMsIG1lc3NhZ2UgPSBGQUxTRX0NCiMgQ2hhbmdpbmcgdGhlIHllYXIgdG8gYSBwYXJhbWV0ZXINCmRvYWNzX2RmICU+JSANCiAgICBmaWx0ZXIoeWVhcihkYXRlKSA9PSBwYXJhbXMkeWVhcikgJT4lIA0KICAgIGdyb3VwX2J5KGNoZW1pY2FsLCBkYXRlKSAlPiUgDQogICAgc3VtbWFyaXNlKHN1bV9pdGVtcyA9IHN1bShpdGVtcykpICU+JSANCiAgICByZWFjdGFibGUoDQogICAgICAgIC4sDQogICAgICAgIGdyb3VwQnkgPSAiY2hlbWljYWwiDQogICAgKQ0KYGBgDQoNCj4gRXhlcmNpc2U6IFRyeSByZS1yZW5kZXJpbmcgdGhlIHJlcG9ydCB3aXRoIHRoZSB5ZWFyIDIwMjEgdXNpbmcgdGhlIFJzdHVkaW8gSURFLg0KDQpDbGljayBvbiB0aGUgdHJpYW5nbGUgbmV4dCB0byAnS25pdCcsICdLbml0IHdpdGggUGFyYW1ldGVycycsIGNoYW5nZSAyMDIwIHRvIDIwMjEuDQoNCiMgUmVzb3VyY2VzDQoNCi0gW1I0RFMgY2hhcHRlciBvbiBSIG1hcmtkb3duXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3ItbWFya2Rvd24uaHRtbCNyLW1hcmtkb3duKQ0KLSBbTkhTLVIgY29tbXVuaXR5IFIgbWFya2Rvd24gd29ya3Nob3BdKGh0dHBzOi8veW91dHUuYmUvUmFNNmZnd01aSXMpDQotIFtDaGVhdCBzaGVldF0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLykNCi0gW1IgbWFya2Rvd24gY29va2Jvb2tdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi1jb29rYm9vay8pDQotIFtSIG1hcmtkb3duOiBUaGUgRGVmaW5pdGl2ZSBHdWlkZV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykNCg==